home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / gcc / ixemlsrc.lha / ixemul / stdio / vfprintf.c < prev    next >
C/C++ Source or Header  |  1996-03-13  |  23KB  |  967 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Chris Torek.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. static char sccsid[] = "@(#)vfprintf.c    5.47 (Berkeley) 3/22/91";
  39. #endif /* LIBC_SCCS and not lint */
  40.  
  41. /*
  42.  * Actual printf innards.
  43.  *
  44.  * This code is large and complicated...
  45.  */
  46.  
  47. #define KERNEL
  48. #include "ixemul.h"
  49.  
  50. #include <math.h>
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <stdarg.h>
  54. #include "local.h"
  55. #include "fvwrite.h"
  56.  
  57. /*
  58.  * Define FLOATING_POINT to get floating point.
  59.  * Define CSH to get a csh-specific version (grr).
  60.  */
  61. #ifndef CSH
  62. #define    FLOATING_POINT
  63. #endif
  64.  
  65. /* end of configuration stuff */
  66.  
  67.  
  68. #ifdef CSH
  69. /*
  70.  * C shell hacks.  Ick, gag.
  71.  */
  72. #undef BUFSIZ
  73. #include "sh.h"
  74.  
  75. int printf(const char *fmt, ...)
  76. {
  77.     FILE f;
  78.     va_list ap;
  79.     int ret;
  80.  
  81.     va_start(ap, fmt);
  82.     f._flags = __SWR;
  83.     f._write = NULL;
  84.     ret = vfprintf(&f, fmt, ap);
  85.     va_end(ap);
  86.     return ret;
  87. }
  88.  
  89. int __sprint(FILE *fp, struct __suio *uio)
  90. {
  91.     register char *p;
  92.     register int n, ch, iovcnt;
  93.     register struct __siov *iov;
  94.  
  95.     /* must allow sprintf to work, might as well allow others too */
  96.     if (fp->_write || fp->_flags & __SSTR) {
  97.         if (uio->uio_resid == 0) {
  98.             uio->uio_iovcnt = 0;
  99.             return (0);
  100.         }
  101.         n = __sfvwrite(fp, uio);
  102.         uio->uio_resid = 0;
  103.         uio->uio_iovcnt = 0;
  104.         return (n);
  105.     }
  106.     iov = uio->uio_iov;
  107.     for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) {
  108.         for (p = iov->iov_base, n = iov->iov_len; --n >= 0;) {
  109. #ifdef CSHPUTCHAR
  110.             ch = *p++;
  111.             CSHPUTCHAR;    /* this horrid macro uses `ch' */
  112. #else
  113. #undef putchar
  114.             putchar(*p++);
  115. #endif
  116.         }
  117.     }
  118.     uio->uio_resid = 0;
  119.     uio->uio_iovcnt = 0;
  120.     return (0);
  121. }
  122.  
  123. #else /* CSH */
  124.  
  125. /*
  126.  * Flush out all the vectors defined by the given uio,
  127.  * then reset it so that it can be reused.
  128.  */
  129. static int __sprint(FILE *fp, struct __suio *uio)
  130. {
  131.     register int err;
  132.  
  133.     if (uio->uio_resid == 0) {
  134.         uio->uio_iovcnt = 0;
  135.         return (0);
  136.     }
  137.     err = __sfvwrite(fp, uio);
  138.     uio->uio_resid = 0;
  139.     uio->uio_iovcnt = 0;
  140.     return (err);
  141. }
  142.  
  143. /*
  144.  * Helper function for `fprintf to unbuffered unix file': creates a
  145.  * temporary buffer.  We only work on write-only files; this avoids
  146.  * worries about ungetc buffers and so forth.
  147.  */
  148. static int
  149. __sbprintf(fp, fmt, ap)
  150.     register FILE *fp;
  151.     const char *fmt;
  152.     va_list ap;
  153. {
  154.     int ret;
  155.     FILE fake;
  156.     unsigned char buf[BUFSIZ];
  157.  
  158.     /* copy the important variables */
  159.     fake._flags = fp->_flags & ~__SNBF;
  160.     fake._file = fp->_file;
  161.     fake._cookie = fp->_cookie;
  162.     fake._write = fp->_write;
  163.  
  164.     /* set up the buffer */
  165.     fake._bf._base = fake._p = buf;
  166.     fake._bf._size = fake._w = sizeof(buf);
  167.     fake._lbfsize = 0;    /* not actually used, but Just In Case */
  168.  
  169.     /* do the work, then copy any error status */
  170.     ret = vfprintf(&fake, fmt, ap);
  171.     if (ret >= 0 && fflush(&fake))
  172.         ret = EOF;
  173.     if (fake._flags & __SERR)
  174.         fp->_flags |= __SERR;
  175.     return (ret);
  176. }
  177.  
  178. #endif /* CSH */
  179.  
  180. #undef BUF
  181.  
  182. #ifdef FLOATING_POINT
  183. #include "floatio.h"
  184.  
  185. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  186. #define    DEFPREC        6
  187.  
  188. static int cvt();
  189.  
  190. #else /* no FLOATING_POINT */
  191.  
  192. #define    BUF        40
  193.  
  194. #endif /* FLOATING_POINT */
  195.  
  196.  
  197. /*
  198.  * Macros for converting digits to letters and vice versa
  199.  */
  200. #define    to_digit(c)    ((c) - '0')
  201. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  202. #define    to_char(n)    ((n) + '0')
  203.  
  204. /*
  205.  * Flags used during conversion.
  206.  */
  207. #undef LONGINT                /* in <intuition/iobsolete.h> */
  208. #define    LONGINT        0x01        /* long integer */
  209. #define    LONGDBL        0x02        /* long double; unimplemented */
  210. #define    SHORTINT    0x04        /* short integer */
  211. #define    ALT        0x08        /* alternate form */
  212. #define    LADJUST        0x10        /* left adjustment */
  213. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  214. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  215.  
  216. int vfprintf(FILE *fp, const char *fmt0, va_list ap)
  217. {
  218.     register char *fmt;    /* format string */
  219.     register int ch;    /* character from fmt */
  220.     register int n;        /* handy integer (short term usage) */
  221.     register char *cp;    /* handy char pointer (short term usage) */
  222.     register struct __siov *iovp;/* for PRINT macro */
  223.     register int flags;    /* flags as above */
  224.     int ret;        /* return value accumulator */
  225.     int width;        /* width from format (%8d), or 0 */
  226.     int prec;        /* precision from format (%.3d), or -1 */
  227.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  228. #ifdef FLOATING_POINT
  229.     char softsign;        /* temporary negative sign for floats */
  230.     double _double;        /* double precision arguments %[eEfgG] */
  231.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  232. #endif
  233.     u_long _ulong;        /* integer arguments %[diouxX] */
  234.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  235.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  236.     int fieldsz;        /* field size expanded by sign, etc */
  237.     int realsz;        /* field size expanded by dprec */
  238.     int size;        /* size of converted field or string */
  239.     char *xdigs = NULL;    /* digits for [xX] conversion */
  240. #define NIOV 8
  241.     struct __suio uio;    /* output information: summary */
  242.     struct __siov iov[NIOV];/* ... and individual io vectors */
  243.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  244.     char ox[2];        /* space for 0x hex-prefix */
  245.  
  246.     /*
  247.      * Choose PADSIZE to trade efficiency vs size.  If larger
  248.      * printf fields occur frequently, increase PADSIZE (and make
  249.      * the initialisers below longer).
  250.      */
  251. #define    PADSIZE    16        /* pad chunk size */
  252.     static char blanks[PADSIZE] =
  253.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  254.     static char zeroes[PADSIZE] =
  255.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  256.  
  257.     /*
  258.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  259.      */
  260. #define    PRINT(ptr, len) { \
  261.     iovp->iov_base = (ptr); \
  262.     iovp->iov_len = (len); \
  263.     uio.uio_resid += (len); \
  264.     iovp++; \
  265.     if (++uio.uio_iovcnt >= NIOV) { \
  266.         if (__sprint(fp, &uio)) \
  267.             goto error; \
  268.         iovp = iov; \
  269.     } \
  270. }
  271. #define    PAD(howmany, with) { \
  272.     if ((n = (howmany)) > 0) { \
  273.         while (n > PADSIZE) { \
  274.             PRINT(with, PADSIZE); \
  275.             n -= PADSIZE; \
  276.         } \
  277.         PRINT(with, n); \
  278.     } \
  279. }
  280. #define    FLUSH() { \
  281.     if (uio.uio_resid && __sprint(fp, &uio)) \
  282.         goto error; \
  283.     uio.uio_iovcnt = 0; \
  284.     iovp = iov; \
  285. }
  286.  
  287.     /*
  288.      * To extend shorts properly, we need both signed and unsigned
  289.      * argument extraction methods.
  290.      */
  291. #define    SARG() \
  292.     (flags&LONGINT ? va_arg(ap, long) : \
  293.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  294.         (long)va_arg(ap, int))
  295. #define    UARG() \
  296.     (flags&LONGINT ? va_arg(ap, u_long) : \
  297.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  298.         (u_long)va_arg(ap, u_int))
  299.  
  300. #ifndef CSH
  301.     /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  302.     if (!fp || cantwrite(fp))
  303.         return (EOF);
  304.  
  305.     /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  306.     if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  307.         fp->_file >= 0)
  308.         return (__sbprintf(fp, fmt0, ap));
  309. #endif /* CSH */
  310.  
  311.     fmt = (char *)fmt0;
  312.     uio.uio_iov = iovp = iov;
  313.     uio.uio_resid = 0;
  314.     uio.uio_iovcnt = 0;
  315.     ret = 0;
  316.  
  317.     /*
  318.      * Scan the format for conversions (`%' character).
  319.      */
  320.     for (;;) {
  321.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  322.             /* void */;
  323.         if ((n = fmt - cp) != 0) {
  324.             PRINT(cp, n);
  325.             ret += n;
  326.         }
  327.         if (ch == '\0')
  328.             goto done;
  329.         fmt++;        /* skip over '%' */
  330.  
  331.         flags = 0;
  332.         dprec = 0;
  333. #ifdef FLOATING_POINT
  334.         fpprec = 0;
  335. #endif
  336.         width = 0;
  337.         prec = -1;
  338.         sign = '\0';
  339.  
  340. rflag:        ch = *fmt++;
  341. reswitch:    switch (ch) {
  342.         case ' ':
  343.             /*
  344.              * ``If the space and + flags both appear, the space
  345.              * flag will be ignored.''
  346.              *    -- ANSI X3J11
  347.              */
  348.             if (!sign)
  349.                 sign = ' ';
  350.             goto rflag;
  351.         case '#':
  352.             flags |= ALT;
  353.             goto rflag;
  354.         case '*':
  355.             /*
  356.              * ``A negative field width argument is taken as a
  357.              * - flag followed by a positive field width.''
  358.              *    -- ANSI X3J11
  359.              * They don't exclude field widths read from args.
  360.              */
  361.             if ((width = va_arg(ap, int)) >= 0)
  362.                 goto rflag;
  363.             width = -width;
  364.             /* FALLTHROUGH */
  365.         case '-':
  366.             flags |= LADJUST;
  367.             goto rflag;
  368.         case '+':
  369.             sign = '+';
  370.             goto rflag;
  371.         case '.':
  372.             if ((ch = *fmt++) == '*') {
  373.                 n = va_arg(ap, int);
  374.                 prec = n < 0 ? -1 : n;
  375.                 goto rflag;
  376.             }
  377.             n = 0;
  378.             while (is_digit(ch)) {
  379.                 n = 10 * n + to_digit(ch);
  380.                 ch = *fmt++;
  381.             }
  382.             prec = n < 0 ? -1 : n;
  383.             goto reswitch;
  384.         case '0':
  385.             /*
  386.              * ``Note that 0 is taken as a flag, not as the
  387.              * beginning of a field width.''
  388.              *    -- ANSI X3J11
  389.              */
  390.             flags |= ZEROPAD;
  391.             goto rflag;
  392.         case '1': case '2': case '3': case '4':
  393.         case '5': case '6': case '7': case '8': case '9':
  394.             n = 0;
  395.             do {
  396.                 n = 10 * n + to_digit(ch);
  397.                 ch = *fmt++;
  398.             } while (is_digit(ch));
  399.             width = n;
  400.             goto reswitch;
  401. #ifdef FLOATING_POINT
  402.         case 'L':
  403.             flags |= LONGDBL;
  404.             goto rflag;
  405. #endif
  406.         case 'h':
  407.             flags |= SHORTINT;
  408.             goto rflag;
  409.         case 'l':
  410.             flags |= LONGINT;
  411.             goto rflag;
  412.         case 'c':
  413.             *(cp = buf) = va_arg(ap, int);
  414.             size = 1;
  415.             sign = '\0';
  416.             break;
  417.         case 'D':
  418.             flags |= LONGINT;
  419.             /*FALLTHROUGH*/
  420.         case 'd':
  421.         case 'i':
  422.             _ulong = SARG();
  423.             if ((long)_ulong < 0) {
  424.                 _ulong = -_ulong;
  425.                 sign = '-';
  426.             }
  427.             base = DEC;
  428.             goto number;
  429. #ifdef FLOATING_POINT
  430.         case 'e':
  431.         case 'E':
  432.         case 'f':
  433.         case 'g':
  434.         case 'G':
  435.             _double = va_arg(ap, double);
  436.             /* do this before tricky precision changes */
  437.             if (isinf(_double)) {
  438.                 if (_double < 0)
  439.                     sign = '-';
  440.                 cp = "Inf";
  441.                 size = 3;
  442.                 break;
  443.             }
  444.             if (isnan(_double)) {
  445.                 cp = "NaN";
  446.                 size = 3;
  447.                 break;
  448.             }
  449.             /*
  450.              * don't do unrealistic precision; just pad it with
  451.              * zeroes later, so buffer size stays rational.
  452.              */
  453.             if (prec > MAXFRACT) {
  454.                 if ((ch != 'g' && ch != 'G') || (flags&ALT))
  455.                     fpprec = prec - MAXFRACT;
  456.                 prec = MAXFRACT;
  457.             } else if (prec == -1)
  458.                 prec = DEFPREC;
  459.             /*
  460.              * cvt may have to round up before the "start" of
  461.              * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
  462.              * if the first character is still NUL, it did.
  463.              * softsign avoids negative 0 if _double < 0 but
  464.              * no significant digits will be shown.
  465.              */
  466.             cp = buf;
  467.             *cp = '\0';
  468.             size = cvt(_double, prec, flags, &softsign, ch,
  469.                 cp, buf + sizeof(buf));
  470.             if (softsign)
  471.                 sign = '-';
  472.             if (*cp == '\0')
  473.                 cp++;
  474.             break;
  475. #endif /* FLOATING_POINT */
  476.         case 'n':
  477.             if (flags & LONGINT)
  478.                 *va_arg(ap, long *) = ret;
  479.             else if (flags & SHORTINT)
  480.                 *va_arg(ap, short *) = ret;
  481.             else
  482.                 *va_arg(ap, int *) = ret;
  483.             continue;    /* no output */
  484.         case 'O':
  485.             flags |= LONGINT;
  486.             /*FALLTHROUGH*/
  487.         case 'o':
  488.             _ulong = UARG();
  489.             base = OCT;
  490.             goto nosign;
  491.         case 'p':
  492.             /*
  493.              * ``The argument shall be a pointer to void.  The
  494.              * value of the pointer is converted to a sequence
  495.              * of printable characters, in an implementation-
  496.              * defined manner.''
  497.              *    -- ANSI X3J11
  498.              */
  499.             /* NOSTRICT */
  500.             _ulong = (u_long)va_arg(ap, void *);
  501.             base = HEX;
  502.             xdigs = "0123456789abcdef";
  503.             flags |= HEXPREFIX;
  504.             ch = 'x';
  505.             goto nosign;
  506.         case 's':
  507.             if ((cp = va_arg(ap, char *)) == NULL)
  508.                 cp = "(null)";
  509.             if (prec >= 0) {
  510.                 /*
  511.                  * can't use strlen; can only look for the
  512.                  * NUL in the first `prec' characters, and
  513.                  * strlen() will go further.
  514.                  */
  515.                 char *p = memchr(cp, 0, prec);
  516.  
  517.                 if (p != NULL) {
  518.                     size = p - cp;
  519.                     if (size > prec)
  520.                         size = prec;
  521.                 } else
  522.                     size = prec;
  523.             } else
  524.                 size = strlen(cp);
  525.             sign = '\0';
  526.             break;
  527.         case 'U':
  528.             flags |= LONGINT;
  529.             /*FALLTHROUGH*/
  530.         case 'u':
  531.             _ulong = UARG();
  532.             base = DEC;
  533.             goto nosign;
  534.         case 'X':
  535.             xdigs = "0123456789ABCDEF";
  536.             goto hex;
  537.         case 'x':
  538.             xdigs = "0123456789abcdef";
  539. hex:            _ulong = UARG();
  540.             base = HEX;
  541.             /* leading 0x/X only if non-zero */
  542.             if (flags & ALT && _ulong != 0)
  543.                 flags |= HEXPREFIX;
  544.  
  545.             /* unsigned conversions */
  546. nosign:            sign = '\0';
  547.             /*
  548.              * ``... diouXx conversions ... if a precision is
  549.              * specified, the 0 flag will be ignored.''
  550.              *    -- ANSI X3J11
  551.              */
  552. number:            if ((dprec = prec) >= 0)
  553.                 flags &= ~ZEROPAD;
  554.  
  555.             /*
  556.              * ``The result of converting a zero value with an
  557.              * explicit precision of zero is no characters.''
  558.              *    -- ANSI X3J11
  559.              */
  560.             cp = buf + BUF;
  561.             if (_ulong != 0 || prec != 0) {
  562.                 /*
  563.                  * unsigned mod is hard, and unsigned mod
  564.                  * by a constant is easier than that by
  565.                  * a variable; hence this switch.
  566.                  */
  567.                 switch (base) {
  568.                 case OCT:
  569.                     do {
  570.                         *--cp = to_char(_ulong & 7);
  571.                         _ulong >>= 3;
  572.                     } while (_ulong);
  573.                     /* handle octal leading 0 */
  574.                     if (flags & ALT && *cp != '0')
  575.                         *--cp = '0';
  576.                     break;
  577.  
  578.                 case DEC:
  579.                     /* many numbers are 1 digit */
  580.                     while (_ulong >= 10) {
  581.                         *--cp = to_char(_ulong % 10);
  582.                         _ulong /= 10;
  583.                     }
  584.                     *--cp = to_char(_ulong);
  585.                     break;
  586.  
  587.                 case HEX:
  588.                     do {
  589.                         *--cp = xdigs[_ulong & 15];
  590.                         _ulong >>= 4;
  591.                     } while (_ulong);
  592.                     break;
  593.  
  594.                 default:
  595.                     cp = "bug in vfprintf: bad base";
  596.                     size = strlen(cp);
  597.                     goto skipsize;
  598.                 }
  599.             }
  600.             size = buf + BUF - cp;
  601.         skipsize:
  602.             break;
  603.         default:    /* "%?" prints ?, unless ? is NUL */
  604.             if (ch == '\0')
  605.                 goto done;
  606.             /* pretend it was %c with argument ch */
  607.             cp = buf;
  608.             *cp = ch;
  609.             size = 1;
  610.             sign = '\0';
  611.             break;
  612.         }
  613.  
  614.         /*
  615.          * All reasonable formats wind up here.  At this point,
  616.          * `cp' points to a string which (if not flags&LADJUST)
  617.          * should be padded out to `width' places.  If
  618.          * flags&ZEROPAD, it should first be prefixed by any
  619.          * sign or other prefix; otherwise, it should be blank
  620.          * padded before the prefix is emitted.  After any
  621.          * left-hand padding and prefixing, emit zeroes
  622.          * required by a decimal [diouxX] precision, then print
  623.          * the string proper, then emit zeroes required by any
  624.          * leftover floating precision; finally, if LADJUST,
  625.          * pad with blanks.
  626.          */
  627.  
  628.         /*
  629.          * compute actual size, so we know how much to pad.
  630.          * fieldsz excludes decimal prec; realsz includes it
  631.          */
  632. #ifdef FLOATING_POINT
  633.         fieldsz = size + fpprec;
  634. #else
  635.         fieldsz = size;
  636. #endif
  637.         if (sign)
  638.             fieldsz++;
  639.         else if (flags & HEXPREFIX)
  640.             fieldsz += 2;
  641.         realsz = dprec > fieldsz ? dprec : fieldsz;
  642.  
  643.         /* right-adjusting blank padding */
  644.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  645.             PAD(width - realsz, blanks);
  646.  
  647.         /* prefix */
  648.         if (sign) {
  649.             PRINT(&sign, 1);
  650.         } else if (flags & HEXPREFIX) {
  651.             ox[0] = '0';
  652.             ox[1] = ch;
  653.             PRINT(ox, 2);
  654.         }
  655.  
  656.         /* right-adjusting zero padding */
  657.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  658.             PAD(width - realsz, zeroes);
  659.  
  660.         /* leading zeroes from decimal precision */
  661.         PAD(dprec - fieldsz, zeroes);
  662.  
  663.         /* the string or number proper */
  664.         PRINT(cp, size);
  665.  
  666. #ifdef FLOATING_POINT
  667.         /* trailing f.p. zeroes */
  668.         PAD(fpprec, zeroes);
  669. #endif
  670.  
  671.         /* left-adjusting padding (always blank) */
  672.         if (flags & LADJUST)
  673.             PAD(width - realsz, blanks);
  674.  
  675.         /* finally, adjust ret */
  676.         ret += width > realsz ? width : realsz;
  677.  
  678.         FLUSH();    /* copy out the I/O vectors */
  679.     }
  680. done:
  681.     FLUSH();
  682. error:
  683.     return (__sferror(fp) ? EOF : ret);
  684.     /* NOTREACHED */
  685. }
  686.  
  687. #ifdef FLOATING_POINT
  688. #include <math.h>
  689.  
  690. static char *exponent();
  691. static char *round();
  692.  
  693. static int
  694. cvt(number, prec, flags, signp, fmtch, startp, endp)
  695.     double number;
  696.     register int prec;
  697.     int flags;
  698.     char *signp;
  699.     int fmtch;
  700.     char *startp, *endp;
  701. {
  702.     register char *p, *t;
  703.     register double fract;
  704.     int dotrim, expcnt, gformat, add_1_to_exp = 1;
  705.     double integer, tmp;
  706.  
  707.     dotrim = expcnt = gformat = 0;
  708.     if (number < 0) {
  709.         number = -number;
  710.         *signp = '-';
  711.     } else
  712.         *signp = 0;
  713.  
  714.     fract = modf(number, &integer);
  715.  
  716.     /* get an extra slot for rounding. */
  717.     t = ++startp;
  718.  
  719.     /*
  720.      * get integer portion of number; put into the end of the buffer; the
  721.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  722.      */
  723.     for (p = endp - 1; integer; ++expcnt) {
  724.         tmp = modf(integer / 10, &integer);
  725.         *p = to_char((int)((tmp + .01) * 10));
  726.         if (*p-- != '9')
  727.           add_1_to_exp = 0;
  728.     }
  729.     if (add_1_to_exp && fract < 0.5)
  730.       add_1_to_exp = 0;
  731.       
  732.     switch (fmtch) {
  733.     case 'f':
  734.         /* reverse integer into beginning of buffer */
  735.         if (expcnt)
  736.             for (; ++p < endp; *t++ = *p);
  737.         else
  738.             *t++ = '0';
  739.         /*
  740.          * if precision required or alternate flag set, add in a
  741.          * decimal point.
  742.          */
  743.         if (prec || flags&ALT)
  744.             *t++ = '.';
  745.         /* if requires more precision and some fraction left */
  746.         if (fract) {
  747.             if (prec)
  748.                 do {
  749.                     fract = modf(fract * 10, &tmp);
  750.                     *t++ = to_char((int)tmp);
  751.                 } while (--prec && fract);
  752.             if (fract)
  753.                 startp = round(fract, (int *)NULL, startp,
  754.                     t - 1, (char)0, signp);
  755.         }
  756.         for (; prec--; *t++ = '0');
  757.         break;
  758.     case 'e':
  759.     case 'E':
  760. eformat:    if (expcnt) {
  761.             *t++ = *++p;
  762.             if (prec || flags&ALT)
  763.                 *t++ = '.';
  764.             /* if requires more precision and some integer left */
  765.             for (; prec && ++p < endp; --prec)
  766.                 *t++ = *p;
  767.             /*
  768.              * if done precision and more of the integer component,
  769.              * round using it; adjust fract so we don't re-round
  770.              * later.
  771.              */
  772.             if (!prec && ++p < endp) {
  773.                 fract = 0;
  774.                 startp = round((double)0, &expcnt, startp,
  775.                     t - 1, *p, signp);
  776.             }
  777.             /* adjust expcnt for digit in front of decimal */
  778.             --expcnt;
  779.         }
  780.         /* until first fractional digit, decrement exponent */
  781.         else if (fract) {
  782.             /* adjust expcnt for digit in front of decimal */
  783.             for (expcnt = -1;; --expcnt) {
  784.                 fract = modf(fract * 10, &tmp);
  785.                 if (tmp)
  786.                     break;
  787.             }
  788.             *t++ = to_char((int)tmp);
  789.             if (prec || flags&ALT)
  790.                 *t++ = '.';
  791.         }
  792.         else {
  793.             *t++ = '0';
  794.             if (prec || flags&ALT)
  795.                 *t++ = '.';
  796.         }
  797.         /* if requires more precision and some fraction left */
  798.         if (fract) {
  799.             if (prec)
  800.                 do {
  801.                     fract = modf(fract * 10, &tmp);
  802.                     *t++ = to_char((int)tmp);
  803.                 } while (--prec && fract);
  804.             if (fract)
  805.                 startp = round(fract, &expcnt, startp,
  806.                     t - 1, (char)0, signp);
  807.         }
  808.         /* if requires more precision */
  809.         for (; prec--; *t++ = '0');
  810.  
  811.         /* unless alternate flag, trim any g/G format trailing 0's */
  812.         if (gformat && !(flags&ALT)) {
  813.             while (t > startp && *--t == '0');
  814.             if (*t == '.')
  815.                 --t;
  816.             ++t;
  817.         }
  818.         t = exponent(t, expcnt, fmtch);
  819.         break;
  820.     case 'g':
  821.     case 'G':
  822.         /* a precision of 0 is treated as a precision of 1. */
  823.         if (!prec)
  824.             ++prec;
  825.         /*
  826.          * ``The style used depends on the value converted; style e
  827.          * will be used only if the exponent resulting from the
  828.          * conversion is less than -4 or greater or equal than the
  829.                  * precision.''
  830.          *    -- ANSI X3J11
  831.          */
  832.         if (expcnt + add_1_to_exp > prec || (!expcnt && fract && fract < .0001)) {
  833.             /*
  834.              * g/G format counts "significant digits, not digits of
  835.              * precision; for the e/E format, this just causes an
  836.              * off-by-one problem, i.e. g/G considers the digit
  837.              * before the decimal point significant and e/E doesn't
  838.              * count it as precision.
  839.              */
  840.             --prec;
  841.             fmtch -= 2;        /* G->E, g->e */
  842.             gformat = 1;
  843.             goto eformat;
  844.         }
  845.         /*
  846.          * reverse integer into beginning of buffer,
  847.          * note, decrement precision
  848.          */
  849.         if (expcnt)
  850.             for (; ++p < endp; *t++ = *p, --prec);
  851.         else
  852.             *t++ = '0';
  853.         /*
  854.          * if precision required or alternate flag set, add in a
  855.          * decimal point.  If no digits yet, add in leading 0.
  856.          */
  857.         if (prec || flags&ALT) {
  858.             dotrim = 1;
  859.             *t++ = '.';
  860.         }
  861.         else
  862.             dotrim = 0;
  863.         /* if requires more precision and some fraction left */
  864.         if (fract) {
  865.             if (prec) {
  866.                 do {
  867.                     fract = modf(fract * 10, &tmp);
  868.                     *t++ = to_char((int)tmp);
  869.                 } while(!tmp);
  870.                 while (--prec && fract) {
  871.                     fract = modf(fract * 10, &tmp);
  872.                     *t++ = to_char((int)tmp);
  873.                 }
  874.             }
  875.             if (fract)
  876.                 startp = round(fract, (int *)NULL, startp,
  877.                     t - 1, (char)0, signp);
  878.         }
  879.         /* alternate format, adds 0's for precision, else trim 0's */
  880.         if (flags&ALT)
  881.             for (; prec--; *t++ = '0');
  882.         else if (dotrim) {
  883.             while (t > startp && *--t == '0');
  884.             if (*t != '.')
  885.                 ++t;
  886.         }
  887.     }
  888.     return (t - startp);
  889. }
  890.  
  891. static char *
  892. round(fract, exp, start, end, ch, signp)
  893.     double fract;
  894.     int *exp;
  895.     register char *start, *end;
  896.     char ch, *signp;
  897. {
  898.     double tmp;
  899.  
  900.     if (fract)
  901.         (void)modf(fract * 10, &tmp);
  902.     else
  903.         tmp = to_digit(ch);
  904.     if (tmp > 4)
  905.         for (;; --end) {
  906.             if (*end == '.')
  907.                 --end;
  908.             if (++*end <= '9')
  909.                 break;
  910.             *end = '0';
  911.             if (end == start) {
  912.                 if (exp) {    /* e/E; increment exponent */
  913.                     *end = '1';
  914.                     ++*exp;
  915.                 }
  916.                 else {        /* f; add extra digit */
  917.                 *--end = '1';
  918.                 --start;
  919.                 }
  920.                 break;
  921.             }
  922.         }
  923.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  924.     else if (*signp == '-')
  925.         for (;; --end) {
  926.             if (*end == '.')
  927.                 --end;
  928.             if (*end != '0')
  929.                 break;
  930.             if (end == start)
  931.                 *signp = 0;
  932.         }
  933.     return (start);
  934. }
  935.  
  936. static char *
  937. exponent(p, exp, fmtch)
  938.     register char *p;
  939.     register int exp;
  940.     int fmtch;
  941. {
  942.     register char *t;
  943.     char expbuf[MAXEXP];
  944.  
  945.     *p++ = fmtch;
  946.     if (exp < 0) {
  947.         exp = -exp;
  948.         *p++ = '-';
  949.     }
  950.     else
  951.         *p++ = '+';
  952.     t = expbuf + MAXEXP;
  953.     if (exp > 9) {
  954.         do {
  955.             *--t = to_char(exp % 10);
  956.         } while ((exp /= 10) > 9);
  957.         *--t = to_char(exp);
  958.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  959.     }
  960.     else {
  961.         *p++ = '0';
  962.         *p++ = to_char(exp);
  963.     }
  964.     return (p);
  965. }
  966. #endif /* FLOATING_POINT */
  967.